#pragma once

#include "Comm.hpp"

#define MAX_LISTEN 1024

class Socket
{
public:
    Socket() : _sockfd(-1) {}

    Socket(int fd) : _sockfd(fd) {}

    // 创建套接字
    bool Create()
    {
        _sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (_sockfd < 0)
        {
            LOG(ERROR, "socket error, errno: %d -> %s\n", errno, strerror(errno));
            exit(SOCKET_ERROR);
        }
        LOG(DEBUG, "Create socket successfully, sockfd: %d\n", _sockfd);
        return true;
    } 

    // 绑定地址信息
    bool Bind(const std::string &ip, in_port_t port)
    {
        struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = ::htons(port);
        addr.sin_addr.s_addr = ::inet_addr(ip.c_str());
        socklen_t len = sizeof(struct sockaddr_in);
        int ret = ::bind(_sockfd, (struct sockaddr *)&addr, len);
        if (ret < 0)
        {
            LOG(ERROR, "sockfd %d bind error, errno: %d -> %s\n", _sockfd, errno, strerror(errno));
            exit(BIND_ERROR);
        }
        LOG(DEBUG, "sockfd %d bind successfully!\n", _sockfd);
        return true;
    }
    
    // 开始监听
    bool Listen(int backlog = MAX_LISTEN)
    {
        int ret = ::listen(_sockfd, backlog);
        if (ret < 0)
        {
            LOG(ERROR, "listen sockfd %d listen error, errno: %d -> %s\n", _sockfd, errno, strerror(errno));
            exit(LISTEN_ERROR);
        }
        LOG(DEBUG, "listen sockfd %d listen successfully!\n", _sockfd);
        return true;
    }

    // 向服务器发起连接
    bool Connect(const std::string &ip, in_port_t port)
    {
        struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = ::htons(port);
        addr.sin_addr.s_addr = ::inet_addr(ip.c_str());
        socklen_t len = sizeof(struct sockaddr_in);
        int ret = ::connect(_sockfd, (struct sockaddr *)&addr, len);
        if (ret < 0)
        {
            LOG(ERROR, "Connect to server[%s:%d] error, errno: %d -> %s\n", ip.c_str(), port, errno, strerror(errno));
            return false;
        }
        LOG(DEBUG, "Connect to server[%s:%d] successfully\n", ip.c_str(), port);
        return true;
    }

    // 获取新连接
    int Accept()
    {
        struct sockaddr_in peer;
        socklen_t len = sizeof(struct sockaddr_in);
        int iosockfd = ::accept(_sockfd, (struct sockaddr *)&peer, &len);
        if (iosockfd < 0)
        {
            LOG(WARNING, "Get new link error, errno: %d -> %s\n", errno, strerror(errno));
            return -1;
        }
        InetAddr addr(peer);
        LOG(DEBUG, "listen sockfd %d get a new link [%s]\n", _sockfd, addr.GetAddrStr().c_str());
        return iosockfd;
    }

    // 接收数据
    ssize_t Recv(void *buf, size_t len, int flag = 0)
    {
        if (len == 0) return 0;
        ssize_t ret = ::recv(_sockfd, buf, len, flag);
        if (ret < 0)
        {
            if (errno == EWOULDBLOCK || errno == EINTR)
            {
                return 0;
            }
            LOG(ERROR, "%d recv error, errno: %d -> %s\n", _sockfd, errno, strerror(errno));
            return -1;
        }
        else if (ret == 0)
        {
            // LOG(INFO, "Peer closed!\n");
            return -1;
        }
        char* char_buf = (char*)buf;
        char_buf[ret] = 0;
        LOG(DEBUG, "recv success, peer: %s\n", char_buf);
        return ret;
    }

    ssize_t NonBlockRecv(void *buf, size_t len)
    {
        return Recv(buf, len, MSG_DONTWAIT); // MSG_DONTWAIT 为非阻塞接收
    }

    // 发送数据
    ssize_t Send(const void *buf, size_t len, int flag = 0)
    {
        if (len == 0) return 0;
        ssize_t ret = ::send(_sockfd, buf, len, flag);
        if (ret < 0)
        {
            if (errno == EWOULDBLOCK || errno == EINTR)
            {
                return 0;
            }
            LOG(ERROR, "send error, errno: %d -> %s\n", errno, strerror(errno));
            return -1;
        }
        else if (ret == 0)
        {
            LOG(WARNING, "Send nothing?\n");
            return 0;
        }
        LOG(DEBUG, "send success!\n");
        return ret;
    }

    ssize_t NonBlockSend(const void *buf, size_t len)
    {
        return Send(buf, len, MSG_DONTWAIT); // MSG_DONTWAIT 为非阻塞发送
    }

    // 关闭套接字
    void Close()
    {
        if (_sockfd >= 0)
        {
            ::close(_sockfd);
            _sockfd = -1;
        }
    }

    // 创建一个服务端连接
    bool CreateServer(in_port_t port, const std::string &ip = "0.0.0.0", bool block_flag = false)
    {
        bool ret;
        if (Create() == false) return false;
        ReuseAddress();
        if (block_flag) NonBlock();
        if (Bind(ip, port) == false) return false;
        if (Listen() == false) return false;
        return true;
    }

    // 创建一个客户端连接
    bool CreateClient(in_port_t port, const std::string &ip)
    {
        if (Create() == false) return false;
        if (Connect(ip, port) == false) return false;
        return true;
    }

    // 设置套接字选项 --> 开启地址重用
    void ReuseAddress()
    {
        int opt = 1;
        ::setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
        opt = 1;
        ::setsockopt(_sockfd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt));
    }

    // 设置套接字属性 --> 设置为非阻塞
    void NonBlock()
    {
        int flag = ::fcntl(_sockfd, F_GETFL, 0);
        if (flag < 0)
        {
            LOG(ERROR, "fcntl get flag error, errno: %d -> %s\n", errno, strerror(errno));
            return;
        }
        if (::fcntl(_sockfd, F_SETFL, flag | O_NONBLOCK) < 0)
        {
            LOG(ERROR, "fcntl set flag error, errno: %d -> %s\n", errno, strerror(errno));
            return;
        }
    }

    int GetFd()
    {
        return _sockfd;
    }

    ~Socket()
    {
        Close();
    }

private:
    int _sockfd;
};

